import com.sun.net.httpserver.*;

import DRC.DRCDB;
import DRC.channel;
import DRC.channel4collect;
import DRC.dataItem;
import DRC.dataItem2channel;
import DRC.dataItem4collect;
import DRC.dataSimulator;
import DRC.protocol;
import DRC.DRModbus.DRModbus_RTU_Master;
import DRC.DRModbus.DRModbus_TCP_Master;
import DRCOMM.DRHTTP_API;
import DRCOMM.DR_SESSION;
import DRCOMM.HttpRequestFormResolver;
import DRCOMM.dr_ajax_answer;
import DRCOMM.dr_html_template;
import DRCOMM.dr_menu;
import DRCOMM.file_reader;

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DRFJW_Handler implements HttpHandler {

    List<String> api_list=new ArrayList<String>();
    public static List<DRHTTP_API> api_lists=new ArrayList<DRHTTP_API>();
    List<String> uri;
    Map<String,DR_SESSION> dr_session=new HashMap<String,DR_SESSION>();

    public DRCDB drcdb;
    public Map<String, Object> parameters = null;

    public DRFJW_Handler(DRCDB drcdb){
        this.drcdb=drcdb;
        // this.api_list.add("show_menu");
        associate_actions(api_lists,drcdb);
        this.api_list.add("shutdown");

        // 关联动作
        try {
            protocol.associate_actions(api_lists,drcdb);
            channel.associate_actions(api_lists,drcdb);
            channel4collect.associate_actions(api_lists,drcdb);
            dataItem.associate_actions(api_lists, drcdb);
            dataItem2channel.associate_actions(api_lists, drcdb);
            dataItem4collect.associate_actions(api_lists, drcdb);
            DRModbus_RTU_Master.associate_actions(api_lists,drcdb);
            DRModbus_TCP_Master.associate_actions(api_lists,drcdb);
            dataSimulator.associate_actions(api_lists, drcdb);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        for(DRHTTP_API api:api_lists){
            this.api_list.add(api.URI);
        }
    }

    public void handle(HttpExchange exchange) throws IOException {
        String requestMethod = exchange.getRequestMethod();
        URI requestedUri = exchange.getRequestURI();
        Headers requestHeaders = exchange.getRequestHeaders();
        OutputStream responseBody = exchange.getResponseBody();
        Headers responseHeaders = exchange.getResponseHeaders();
        String path=requestedUri.getPath();
        this.parameters = new HashMap<String, Object>();
        System.out.println("get new request:"+path);
        // 获取uri参数，区分GET和POST
        // 获取到的参数保存在 this.parameters 中，可通过 get(key) 取得
        // 其中key为参数名
        if (requestMethod.equalsIgnoreCase("GET")) {
            // 获取资源路径
            // 获取URI参数
            String query = requestedUri.getRawQuery();
            parseQuery(query, this.parameters);
        }else{
            String contentType = requestHeaders.getFirst("Content-type");
            if(contentType!=null&&contentType.substring(0, 30).equals("multipart/form-data; boundary=")){
                System.out.println(contentType);
                // List<HttpRequestFormResolver.ParamItem> params = HttpRequestFormResolver.resolveForm(requestHeaders, exchange.getRequestBody());
                this.parameters = HttpRequestFormResolver.resolveForm(requestHeaders, exchange.getRequestBody(),this.parameters);
            }else{
                InputStreamReader isr = new InputStreamReader(exchange.getRequestBody(), "utf-8");
                BufferedReader br = new BufferedReader(isr);
                String query = br.readLine();
                parseQuery(query, this.parameters);
            }
        }
        String filename;
        String token="";
        // 去掉前面的 "/",取得后面的内容
        filename=path.substring(1);
        String Cookie="";
        if(requestHeaders.containsKey("Cookie")){
            Cookie=requestHeaders.get("Cookie").toString();
        }
        responseHeaders.set("Connection","Keep-Alive");
        responseHeaders.set("Keep-Alive","timeout=5, max=100");
        responseHeaders.set("Server","DRFPS v0.1");
        // 在Cookie中获取token
        String pattern = "DRSESSID=(\\w+)";
        // 创建 Pattern 对象
        Pattern r = Pattern.compile(pattern);
        // 创建 matcher 对象
        Matcher m = r.matcher(Cookie);
        if(m.find()){
            token=m.group(1);
            // System.out.println(token);
        }
        // 处理session内容
        int dr_session_count=0;
        DR_SESSION drs=null;
        if(Cookie.equals("")){
            String uuid = UUID.randomUUID().toString().replace("-", "");
            responseHeaders.set("Set-cookie","DRSESSID="+uuid+";Max-Age=3600; Path=/;");
            dr_session.put(token, new DR_SESSION(token));
            System.out.println("create new session!");
        }else{
            if(dr_session.containsKey(token)){
                drs=dr_session.get(token);
                dr_session_count=Integer.valueOf(drs.get("count"));
                dr_session_count++;
                drs.put("count", Integer.toString(dr_session_count));
                dr_session.put(token, drs);
            }else{
                drs=new DR_SESSION(token);
                drs.put("count", Integer.toString(1));
                dr_session.put(token, drs);
            }
            // System.out.printf("Cookie:[%s],count:[%s]\n",Cookie,drs.get("count"));
        }

        this.uri=Arrays.asList(filename.split("/"));
        if(filename.equals(""))filename="index.html";
        String content="";
        if(this.api_list.contains(filename)){
            String api_name=filename;
            for(DRHTTP_API api:api_lists){
                if(api.URI.equals(api_name)){
                    content=api.getResult(this.parameters,drs);
                    break;
                }
            }
            if(api_name.equals("shutdown")){
                this.shutdown(exchange,responseHeaders, responseBody);
            }else if(api_name.equals("farm/read_EText_farm_period_predict_data")){
                this.read_EText_farm_period_predict_data(exchange,responseHeaders,responseBody,
                this.get_parameters(this.parameters,"filename"));
                return;
            }else if(api_name.equals("farm/run_host_check")){
                this.run_host_check(exchange,responseHeaders, responseBody,
                this.get_parameters(this.parameters,"time"));
                return;
            }
            this.send_json(exchange, responseHeaders, responseBody, content);
        }else{
            if(!filename.substring(0,6).equals("static"))
                filename="./templates/"+filename;
            else
                filename="."+path;
            // 取得访问资料地址
            try {
                // 如果存在文件则以html输出
                if(filename.substring(filename.length()-4).equals("html")||filename.substring(filename.length()-3).equals("htm")){
                    responseHeaders.set("Content-Type", "text/html; charset=utf-8");
                    exchange.sendResponseHeaders(200, 0);
                    content=dr_html_template.read_html_template(filename);
                    responseBody.write((content).getBytes("UTF-8"));
                }else{
                    String sub_filename=filename;
                    if(filename.indexOf("?")>0){
                        sub_filename=filename.substring(filename.lastIndexOf("/")+1,filename.lastIndexOf("?"));
                    }else{
                        sub_filename=filename.substring(filename.lastIndexOf("/")+1);
                    }
                    if(sub_filename.substring(sub_filename.length()-2).equals("js")){
                        responseHeaders.set("Content-Type", "text/html; charset=utf-8");
                        exchange.sendResponseHeaders(200, 0);
                        content = file_reader.read_file2string(filename);
                        responseBody.write((content).getBytes("UTF-8"));
                        responseBody.flush();
                        responseBody.close();
                    }else if(sub_filename.substring(sub_filename.length()-3).equals("css")){
                        responseHeaders.set("Content-Type", "text/css; charset=utf-8");
                        exchange.sendResponseHeaders(200, 0);
                        content = file_reader.read_file2string(filename);
                        responseBody.write((content).getBytes("UTF-8"));
                        responseBody.flush();
                        responseBody.close();
                    }else{
                        try {
                            byte[] fileBytes = file_reader.read_file2bytes(filename);
                            exchange.getResponseHeaders().add("Content-Disposition", "attachment;filename="+sub_filename);
                            exchange.getResponseHeaders().add("Content-Length", String.valueOf(fileBytes.length));
                            exchange.sendResponseHeaders(200, 0);
                            responseBody.write(fileBytes);
                        }catch(Exception e){

                        } finally {
                            responseBody.flush();
                            responseBody.close();
                        }
                    }
                }         
            } catch (Exception e) {
                // 否则以文本输出
                exchange.sendResponseHeaders(404, 0);
                responseHeaders.set("Content-Type", "text/plain; charset=utf-8");
                responseBody.write(("file not exist!!\n").getBytes());
            }
            responseBody.close();
        }
    }

    public static void parseQuery(String query, Map<String, 
        Object> parameters) throws UnsupportedEncodingException {
         if (query != null) {
            String pairs[] = query.split("[&]");
            for (String pair : pairs) {
                String param[] = pair.split("[=]");
                String key = null;
                String value = null;
                if (param.length > 0) {
                    key = URLDecoder.decode(param[0],"UTF-8");
                }

                if (param.length > 1) {
                    value = URLDecoder.decode(param[1],"UTF-8");
                }

                if (parameters.containsKey(key)) {
                    Object obj = parameters.get(key);
                    if (obj instanceof List<?>) {
                        List<String> values = new ArrayList<String>();
                        values.add(value);
                    } else if (obj instanceof String) {
                        List<String> values = new ArrayList<String>();
                        values.add((String) obj);
                        values.add(value);
                        parameters.put(key, values);
                    }
                } else {
                    parameters.put(key, value);
                }
            }
        }
    }

    private String get_parameters(Map<String,Object> parameters,String key){
        String result="";
        if(this.parameters.containsKey(key)){
            if(this.parameters.get(key)!=null)
                result=this.parameters.get(key).toString();
        }
        return result;
    }

    // private Object get_parameterItem(Map<String,Object> parameters,String key){
    //     HttpRequestFormResolver.ParamItem result=null;
    //     if(this.parameters.containsKey(key)){
    //         if(this.parameters.get(key)!=null)
    //             return this.parameters.get(key);
    //     }
    //     return result;
    // }

    private void send_json(HttpExchange exchange,Headers responseHeaders
        ,OutputStream responseBody,String content) 
        throws IOException{
        responseHeaders.set("Content-Type", "application/json; charset=utf-8");
        exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, content.getBytes(StandardCharsets.UTF_8).length);
        responseBody.write(content.getBytes(StandardCharsets.UTF_8));
        responseBody.close();
    }

    public static void associate_actions(List<DRHTTP_API> api_lists,DRCDB drcdb){
        api_lists.add(show_menu(drcdb));
    }

    public static DRHTTP_API show_menu(DRCDB drcdb){
        return new DRHTTP_API(drcdb,"show_menu"){
            @Override
            public String getResult(Map<String, Object> parameters,DR_SESSION drs){
                String content="";
                List<dr_menu> fps_menu=new ArrayList<dr_menu>();
                dr_menu dm1=new dr_menu("c1", "", 1, "通信管理");
                dr_menu dm11=new dr_menu("c11", "channel/channel-list.html", 11, "服务通道");
                dr_menu dm12=new dr_menu("c12", "channel4collect/channel4collect-list.html", 11, "采集通道");
                dm1.add_children(dm11);
                dm1.add_children(dm12);
                fps_menu.add(dm1);
                dr_menu dm2=new dr_menu("c2", "", 2, "定时管理");
                dr_menu dm21=new dr_menu("c21", "schedule/schedule-list.html", 21, "短期预测定时");
                dm2.add_children(dm21);
                fps_menu.add(dm2);
                dr_menu dm3=new dr_menu("c3", "", 3, "预测数据");
                dr_menu dm31=new dr_menu("c31", "farm_period_predict_data/farm_period_predict_data-list.html", 31, "短期预测数据");
                dr_menu dm32=new dr_menu("c32", "farm_period_predict_data/EText_to_farm_period_predict_record-list.html", 32, "短期采集记录");
                dm3.add_children(dm31);
                dm3.add_children(dm32);
                fps_menu.add(dm3);
                dr_menu dm4=new dr_menu("c4", "", 4, "设定管理");
                dr_menu dm41=new dr_menu("c41", "host_setting/host_setting-list.html", 41, "主机设置");
                dm4.add_children(dm41);
                fps_menu.add(dm4);
                dr_menu dm5=new dr_menu("c5", "", 5, "数据绑定");
                dr_menu dm51=new dr_menu("c51", "data_bind/data_bind-list.html", 51, "数据绑定");
                dm5.add_children(dm51);
                fps_menu.add(dm5);
                dr_menu dm6=new dr_menu("c6", "", 6, "数据模拟");
                dr_menu dm61=new dr_menu("c61", "dataSimulator/dataSimulator-list.html", 61, "数据模拟");
                dm6.add_children(dm61);
                fps_menu.add(dm6);
                content=dr_menu.get_answer_json_str(0, "",fps_menu);
                return content;
            }
        };
    }
    private void shutdown(HttpExchange exchange,Headers responseHeaders,OutputStream responseBody) 
        throws IOException{
        responseHeaders.set("Content-Type", "application/json; charset=utf-8");
        String content="";
        dr_ajax_answer daa=new dr_ajax_answer(0, "Server shutdown");
        content=daa.json_string();
        exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, content.getBytes(StandardCharsets.UTF_8).length);
        responseBody.write(content.getBytes(StandardCharsets.UTF_8));
        responseBody.close();
        System.out.println("Server shutdown!");
        System.exit(0);
    }

    private void read_EText_farm_period_predict_data(HttpExchange exchange,
        Headers responseHeaders,OutputStream responseBody,
        String time)throws IOException{
        responseHeaders.set("Content-Type", "application/json; charset=utf-8");
        String content="";
        dr_ajax_answer daa;
        try {
            daa=new dr_ajax_answer(0, "success!");
        } catch (Exception e) {
            daa=new dr_ajax_answer(1, "unknow error!");
        }
        content=daa.json_string();
        exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, content.getBytes(StandardCharsets.UTF_8).length);
        responseBody.write(content.getBytes(StandardCharsets.UTF_8));
        responseBody.close();
    }

    private void run_host_check(HttpExchange exchange,
        Headers responseHeaders,OutputStream responseBody,
        String time)throws IOException{
        responseHeaders.set("Content-Type", "application/json; charset=utf-8");
        String content="";
        dr_ajax_answer daa;
        try {
            daa=new dr_ajax_answer(0, "success!");
        } catch (Exception e) {
            daa=new dr_ajax_answer(1, "unknow error!");
        }
        content=daa.json_string();
        exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, content.getBytes(StandardCharsets.UTF_8).length);
        responseBody.write(content.getBytes(StandardCharsets.UTF_8));
        responseBody.close();
    }

}
